<?php

namespace mini;

use ErrorException;

class App
{
    public function start()
    {
        $data = $this->get_segments();
        define('SEGMENTS', $data['segments']);
        define('ASSUMED_URL', $data['assumed_url']);

        Session::start();

        // 设置中国时区
        date_default_timezone_set(config('timezone'));

        // 设置调试模式
        if (config('debug')) {
            // 显示所有错误
            error_reporting(E_ALL);
            ini_set('display_errors', '1');
        } else {
            // 关闭所有错误
            error_reporting(0);
            ini_set('display_errors', '0');
        }

        // 自定义异常
        set_error_handler('mini\App::errorHandler');
        set_exception_handler('mini\App::exceptionHandler');

        // 追踪调试
        $GLOBALS['traceSql'] = [];

        // 解析路由和应用中的资源文件
        if (strpos(ASSUMED_URL, MODULE_ASSETS_TRIGGER) === false) {
            $this->serve_controller();
        } else {
            $this->serve_app_asset();
        }

        // 开启调试追踪
        if (config('trace')) {
            include __DIR__.'/templates/trace.php';
        }
    }

    /**
     * 路由解析
     */
    private function serve_controller()
    {
        $url = $this->split_url();

        // 如果控制器名等于默认控制器名，则访问模块默认首页
        if (isset($url[1]) && strcmp($url[1], config('default_controller')) === 0) {
            $url[1] = $url[0];
        }

        $module_name     = $url[0];  // 模块名
        $controller_name = $url[1];  // 控制器名
        $method_name     = $url[2];  // 方法名

        // 控制器文件 [双层目录]
        $controller_file = ROOT_PATH.'app/'.$module_name.'/controllers/'.ucfirst($controller_name).'.php';
        // 模型与控制器同名
        $same_name_file = ROOT_PATH.'app/'.$module_name.'/controllers/'.ucfirst($module_name).'.php';

        // 如果控制器文件不存在
        if (!is_file($controller_file)) {
            // 如果有模块与控制器同名的文件
            if (is_file($same_name_file)) {

                // 定义模块名、控制器名、方法名
                define('MODULE_NAME', $module_name);
                define('CONTROLLER_NAME', $module_name);
                define('METHOD_NAME', $controller_name);
                define('FRAME_URL', implode('/', $url));

                // 不使用 composer, 这里需要加载并实例化类文件
                $controller_class = "\\app\\" . $module_name . "\\controllers\\" . ucfirst($module_name);
                // require_once $same_name_file;
                $controller = new $controller_class;

                if (config('debug')) {
                    $this->attempt_sql_transfer($same_name_file);
                }

                // 如果对应方法名存在
                if (method_exists($controller, $controller_name)) {
                    call_user_func([$controller, $controller_name]);
                } else {
                    // 返回 404 页面
                    return abort(404);
                }
            }
        } else {
            // 反之，如果控制器文件存在
            if (is_file($controller_file)) {
                // 定义模块名、控制器名、方法名
                define('MODULE_NAME', $module_name);
                define('CONTROLLER_NAME', $controller_name);
                define('METHOD_NAME', $method_name);
                define('FRAME_URL', implode('/', $url));

                // 不使用 composer, 这里需要加载并实例化类文件
                $controller_class = "\\app\\" . $module_name . "\\controllers\\" . ucfirst($controller_name);
                $controller = new $controller_class;

                if (method_exists($controller, $method_name)) {
                    call_user_func([$controller, $method_name]);
                } else {
                    return abort(404);
                }
            }
        }

        // 如果都不存在，返回 404
        if (!is_file($controller_file) && !is_file($same_name_file)) {
            return abort(404);
        }

        // define('SERVER_ROOT', str_replace('public/index.php', '', $_SERVER['PHP_SELF']));

        // 用于运行追踪
        // $GLOBALS['traceSql'] = [];

        // define('FRAME_URL', implode('/', $url));
    }

    /**
     * 解析路由中的资源文件
     */
    private function serve_app_asset() {

        $url_segments = SEGMENTS;

        foreach ($url_segments as $url_segment_key => $url_segment_value) {
            $pos = strpos($url_segment_value, MODULE_ASSETS_TRIGGER);

            if (is_numeric($pos)) {
                $target_module = str_replace(MODULE_ASSETS_TRIGGER, '', $url_segment_value);
                $file_name = $url_segments[count($url_segments)-1];

                $target_dir = '';
                for ($i=$url_segment_key+1; $i < count($url_segments)-1; $i++) {
                    $target_dir.= $url_segments[$i];
                    if ($i<count($url_segments)-2) {
                        $target_dir.= '/';
                    }
                }

                $asset_path = APP_PATH.strtolower($target_module).'/assets/'.$target_dir.'/'.$file_name;

                if (file_exists($asset_path)) {
                    $content_type = mime_content_type($asset_path);

                    if ($content_type === 'text/plain' || $content_type === 'text/html') {

                        $pos2 = strpos($file_name, '.css');
                        if (is_numeric($pos2)) {
                            $content_type = 'text/css';
                        }

                        $pos2 = strpos($file_name, '.js');
                        if (is_numeric($pos2)) {
                            $content_type = 'text/javascript';
                        }

                    }

                    if ($content_type === 'image/svg') {
                        $content_type.= '+xml';
                    }

                    // 确保不是 PHP 文件或 api.json
                    if((is_numeric(strpos($content_type, 'php'))) || ($file_name === 'api.json')) {
                        http_response_code(422);
                        die();
                    }

                    header('Content-type: '.$content_type);
                    $contents = file_get_contents($asset_path);
                    echo $contents;
                    die();
                }
            }
        }

    }

    /**
     * 获取并拆分 URL
     */
    private function get_segments()
    {
        $assumed_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] .  $_SERVER['REQUEST_URI'];

        $data['assumed_url'] = $assumed_url;

        $assumed_url = str_replace('://', '/', $assumed_url);
        $assumed_url = rtrim($assumed_url, '/');

        $segments = explode('/', $assumed_url);

        $data['segments'] = array_values($segments);

        return $data;
    }

    /**
     * 获取并拆分 URL
     */
    private function split_url()
    {
        if (isset($_GET['url'])) {
            $url = trim($_GET['url'], '/');
            $url = filter_var($url, FILTER_SANITIZE_URL);
            unset($_GET['url']);
        } else {
            $url = config('default_module') . '/' . config('default_controller') . '/' . config('default_method');
        }

        $router = explode('/', $url);

        if (empty($router[0])) {
            array_shift($router);
        }

        /**
         * 自定义路由
         */
        if (config('route')) {
            $routes = require(ROOT_PATH . 'config/routes.php');

            foreach ($routes as $pattern => $route) {
                // 将通配符转换为正则表达式
                $pattern = preg_replace('/:(\w+)/', '(?P<\1>[^/]+)', $pattern);

                // 检查路由是否匹配
                if (preg_match('#^' . $pattern . '$#', $requestedPath, $matches)) {
                    // 提取参数
                    $params = [];
                    foreach ($route['params'] as $key => $regex) {
                        if (isset($matches[$key]) && preg_match('#^' . $regex . '$#', $matches[$key])) {
                            $params[$key] = $matches[$key];
                        } else {
                            // 参数不匹配，跳过这个路由
                            continue 2;
                        }
                    }

                    // 设置路由信息
                    $newRouter = [
                        'module'     => $route['module'],
                        'controller' => $route['controller'],
                        'action'     => $route['action'],
                        'params'     => $params
                    ];

                    return $newRouter;
                }
            }
        }

            // if (array_key_exists($router[0], $routes)) {
            //     $newRouter    = [];
            //     $newRouter[0] = $routes[$router[0]][0];
            //     $newRouter[1] = $routes[$router[0]][1];
            //     $newRouter[2] = $routes[$router[0]][2];

            //     if (!empty($newRouter[2]) && is_array($newRouter[2])) {
            //         $newRouter = $newRouter + $newRouter[2];
            //     }

            //     // dd($newRouter);

            //     define("PAGE_NUMBER",  1);
            //     return $newRouter;
            // };
        

        $router[0] = isset($router[0]) ? $router[0] : config('default_module');
        $router[1] = isset($router[1]) ? $router[1] : config('default_controller');
        $router[2] = isset($router[2]) ? $router[2] : config('default_method');

        // dump(FRAME_URL);

        for ($i = 2; $i < count($router); $i++) {
            if (preg_match('/^page_(.*)()*$/Ui', $router[$i], $matches)) {
                define("PAGE_NUMBER",  intval($matches[1]));
                array_splice($router, $i, 1);
            }
        }

        if (!defined("PAGE_NUMBER")) {
            define("PAGE_NUMBER",  1);
        }

        return $router;
    }

    private function attempt_sql_transfer($controller_path) {
        $ditch = 'controllers/'.CONTROLLER_NAME.'.php';
        $dir_path = str_replace($ditch, '', $controller_path);

        $files = [];
        foreach (glob($dir_path."*.sql") as $file) {
            $file = str_replace($controller_path, '', $file);
            $files[] = $file;
        }

        if (count($files)>0) {
            require_once('tg_transferer/index.php');
            die();
        }

    }

    /**
     * 设置用户自定义的错误处理程序，然后触发错误。
     *
     * @param int    $code     错误编码
     * @param string $message  错误消息
     * @param string $file     引发错误的文件名
     * @param int    $line     引发错误所在行
     *
     * @return void
     */
    public static function errorHandler($level, $message, $file, $line): void
    {
        if (error_reporting() !== 0) {
            throw new ErrorException($message, 0, $level, $file, $line);
        }
    }

    /**
     * 异常处理
     *
     * @param Exception $exception  异常
     *
     * @return void
     */
    public static function exceptionHandler($exception)
    {
        // Code is 404 (not found) or 500 (general error)
        $code = $exception->getCode();
        if ($code != 404) {
            $code = 500;
        }
        http_response_code($code);

        if (config('debug')) {
            include 'templates/debug.php';
            die();
        } else {
            $log = new Log();
            $log->debug($exception->getMessage() . '\n' . $exception->getFile() . '\n' . $exception->getLine());
            return $code;
        }
    }
}
